use alloc::collections::VecDeque;
use alloc::{sync::Arc, vec::Vec};
use core::any::Any;
use spin::Mutex;
/// Trait for block devices
/// which reads and writes data in the unit of blocks
pub trait BlockDevice: Send + Sync + Any {
    ///Read data form block to buffer
    fn read_block(&self, block_id: usize, buf: &mut [u8]);
    ///Write data from buffer to block
    fn write_block(&self, block_id: usize, buf: &[u8]);
}
/// 块大小
pub const BLOCK_SIZE: usize = 512;

/// 块管理器
pub struct BlockManager {
    // 目前只考虑一种设备，一个设备应该是与某种固定的文件系统绑定的，这里是FAT32
    pub(crate) device: Arc<dyn BlockDevice>,
    pub(crate) cache: Arc<Mutex<VecDeque<Block>>>,
    pub(crate) cache_number: usize,
}

impl BlockManager {
    /// 读取一个块
    pub fn read_block(&self, id: usize, buf: &mut [u8; BLOCK_SIZE]) {
        let cache_lock = self.cache.lock();
        let cache = &(*cache_lock);
        // 先查找缓冲区
        for blk in cache {
            if blk.id == id {
                buf.copy_from_slice(&blk.data[..BLOCK_SIZE]);
                return;
            }
        }
        drop(cache_lock);
        // 在缓存中没有找到
        //println!("not found in cache");
        let mut new_block = Block {
            id,
            data: [0; BLOCK_SIZE],
        };
        // 这里将一个[u8; 512] 的引用传递给 &mut [u8], 编译没报错, 这是对的吗？
        //self.device.read_block(id, &new_block.data);
        //println!("read block {}", id);
        self.device.read_block(id, &mut new_block.data);
        // 拷贝数据
        buf.copy_from_slice(&new_block.data[..BLOCK_SIZE]);
        // 更新缓冲区
        let cache = &mut (*self.cache.lock());
        cache.push_back(new_block);
        if cache.len() > self.cache_number {
            cache.pop_front();
        }
    }
}

//#[derive(Debug)]
/// 一个块
pub struct Block {
    pub(crate) id: usize,
    pub(crate) data: [u8; BLOCK_SIZE],
}

impl Block {
    /// Get a immutable reference to the data in the block cache according to the offset.
    //pub fn new(id: usize, ) -> Self {

    //}
    pub fn get_ref<T>(&self, offset: usize) -> &T
    where
        T: Sized,
    {
        let type_size = core::mem::size_of::<T>();
        assert!(offset + type_size <= BLOCK_SIZE);
        unsafe { &*(self.data.as_ptr().add(offset) as *const T) }
        //unsafe { &*(self.data[offset] as *const T) }
    }

    /// 将一个块的内容作为某个数据结构使用
    pub fn use_as<T, V>(&self, offset: usize, f: impl FnOnce(&T) -> V) -> V {
        f(self.get_ref(offset))
    }
}
